﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RootBaseFramework
{
    public abstract class RootEntityBase<TKey> : IBloodLine
        where TKey : struct
    {

  

        public TKey EntityId { get; set; }

        public TKey? ParentId { get; set; }     

        RootEntityBase<TKey> _Parent;
        public RootEntityBase<TKey> Parent
        { 
            get
            {
                return _Parent;
            }
            set
            {

                Policy.RootEntiyBase.IsParentValid policy = new Policy.RootEntiyBase.IsParentValid(this);

                if (policy.IsSatisfiedBy(value))
                {
                    _Parent = value;
                    TraceBloodLine();
                }
                else
                {
                    //do nothing;
                }

               
               
            }
        }

        public virtual  void TraceBloodLine(char delimeter = '`')
    {
                  

        _delimeter = delimeter;
          string bloodline = string.Empty;
          if (Parent != null)
          {
              
            
              bloodline = Parent.BloodLine;
              this.ParentId = Parent.EntityId;
              bloodline = bloodline  + this.EntityId.ToString() + delimeter;



          }
          else//root
          {
              bloodline = delimeter + this.EntityId.ToString() + delimeter;

          }


          BloodLine = bloodline;

          UpdateBloodLines();
    }

        private void UpdateBloodLines()
        {



            var q = GetMyLines(MyRepo,MyUnitOfWork);

            foreach (RootEntityBase<TKey> item in q)
            {
                if(!string.IsNullOrEmpty( OldBloodLine))
                item.BloodLine = item.BloodLine.Replace(OldBloodLine,BloodLine);
            }

            var Uow = (RootBaseFramework.Infra.Data.UnitOfWork)MyUnitOfWork;
            Uow.Commit();
            
        }


        Domain.IRepository<RootEntityBase<TKey>,TKey> _myRepo;
        public Domain.IRepository<RootEntityBase<TKey>, TKey> MyRepo { get { return _myRepo; } }
        Infra.Data.UnitOfWork _myUnitOfWork;
        public Infra.Data.UnitOfWork MyUnitOfWork { get { return _myUnitOfWork; } }


        //public abstract List<Object> GetMyLines(object Repo, object uWork);

        public List<RootEntityBase<TKey>> GetMyLines(Domain.IRepository<RootEntityBase<TKey>, TKey> Repo, Infra.Data.UnitOfWork UWork)
        {
            //if (UWork == null)
            //{
            //    var context = new Service.Repository.Database.RootBaseTestContext();
            //    UWork = new RootBaseFramework.Infra.Data.UnitOfWork(context);
            //}

           // var uWork = (RootBaseFramework.Infra.Data.UnitOfWork)UWork;

            //if (Repo == null)
            //{
            //    Repo = new Service.Repository.Database.PersonRepository(uWork);
            //}

          

           // var repo = (Service.Repository.Database.PersonRepository)Repo;

            if (SetRepository(Repo, UWork))
            {

                var q = MyRepo.FindAll(p => p.BloodLine.StartsWith(OldBloodLine)).ToList();
                return q.ToList();
            }
            else
            {
                return new List<RootEntityBase<TKey>>();
            }


           
            //var q1 = q.Where(p => p.BloodLine.StartsWith(OldBloodLine));
            //return q1.Cast<object>().ToList();
        }


        protected bool SetRepository(Domain.IRepository<RootEntityBase<TKey>, TKey> Repo, Infra.Data.UnitOfWork UWork)
        {
            if (Repo == null || UWork == null)
            {
                return false;
            }
            else
            {
                _myUnitOfWork = UWork;
                _myRepo = Repo;
                return true;
            }

        }
   
        
        string _bloodLine;
    public   string BloodLine
        {
            get
            {
                if (string.IsNullOrEmpty(_bloodLine))
                    _bloodLine = string.Empty; //Delimeter.ToString();
                return _bloodLine;
            }
            set
            {
                _oldBloodLine = BloodLine;
                _bloodLine = value;
            }
        }

    string _oldBloodLine;
    public string OldBloodLine { get { return _oldBloodLine;} }


    private char _delimeter = '`';
    public char Delimeter
    {
        get
        {            
            return _delimeter;
        }
    }
    }

    

    #region ModelConfiguration Sample

  //  class PersonConfiguration
  //: EntityTypeConfiguration<Person>
  //  {

  //      public PersonConfiguration()
  //      {


  //          HasKey(c => c.EntityId)
  //         .Property(c => c.EntityId)
  //         .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);


  //          ToTable("Person");

  //          HasMany(c => c.Children).WithOptional().HasForeignKey(c => c.ParentId).WillCascadeOnDelete(false);


  //      }
  //  }

    #endregion


    public interface IGetTypeInterface
    {
        // Any class that implements IGetTypeInterface must define a method
        // that matches the following signature.
        Type GetTypeOfId();

    }

    public interface IBloodLine
    {
         string BloodLine { get; set; }
         char Delimeter { get; }


    }
}
